import { PayloadAction, createAsyncThunk, createSlice, isRejected } from "@reduxjs/toolkit";
import { GetParams, InventoryEntry, PageInfo, int } from "../types";
import { deleteRequest, getRequest, postRequest, putRequest } from "../util/Net";
import { RootState } from "./store";

// 1. Requests.

type GetInventoryRequest = GetParams & {
  name?: string;
};

interface StockInventoryRequest {
  quantity: number;
}

interface TransferInventoryEntry {
  id: int;
  quantity: number;
}

interface TransferInventoryRequest {
  destination: int;
  transferInventories: TransferInventoryEntry[];
}

interface DeleteInventoryRequest {
  id: string;
}

// 2. Responses.

type GetInventoryResponseEntry = InventoryEntry;

type GetInventoryResponse = PageInfo<GetInventoryResponseEntry>;

// 3. Params for reducers.

type GetInventoryParams = GetInventoryRequest & {
  warehouseId: int;
};

type StockInventoryParams = StockInventoryRequest & {
  warehouseId: int;
  commodityId: int;
  supplierId: int;
};

type TransferInventoryParams = TransferInventoryRequest & {
  warehouseId: int;
};

interface DeleteInventoryParams {
  warehouseId: int;
  id: int[];
}

interface SwitchInventoryParams {
  warehouseId: int;
}

// 4. State and initial value definition.

interface InventoryManagementState {
  warehouseId: int;
  loaded: boolean;
  entries: InventoryEntry[];
}

const initialState: InventoryManagementState = {
  warehouseId: 0,
  loaded: false,
  entries: []
};

// 5. Async functions definition.

const getInventory = createAsyncThunk('inventory/get', async (params: GetInventoryParams) => {
  const response = await getRequest<GetInventoryResponse, GetInventoryRequest>({
    url: `/warehouse/${params.warehouseId}/items`,
    params: {
      page: params.page,
      pageSize: params.pageSize,
      name: params.name
    }
  });
  return response.data;
});

const stockInventory = createAsyncThunk('inventory/stock', async (params: StockInventoryParams) => {
  const response = await postRequest<null, null, StockInventoryRequest>({
    url: `/warehouse/${params.warehouseId}/items/commodity/${params.commodityId}/supplier/${params.supplierId}`,
    params: {
      quantity: params.quantity
    }
  });
  return response.data;
});

const updateInventory = createAsyncThunk('inventory/update', async () => {

});

const transferInventory = createAsyncThunk('inventory/transfer', async (params: TransferInventoryParams) => {
  const response = await postRequest<null, TransferInventoryRequest>({
    url: `/warehouse/${params.warehouseId}/items/transfer`,
    request: {
      destination: params.destination,
      transferInventories: params.transferInventories
    }
  });
  return response.data;
});

const deleteInventory = createAsyncThunk('inventory/delete', async (params: DeleteInventoryParams) => {
  const response = await deleteRequest<null, null, DeleteInventoryRequest>({
    url: `/warehouse/${params.warehouseId}/items`,
    params: {
      id: params.id.join(',')
    }
  });
  return response.data;
});

// 6. Slice definition.

const inventoryManagementSlice = createSlice({
  name: 'inventoryManagement',
  initialState: initialState,
  reducers: {
    clear: (state) => {
      state.warehouseId = 0;
      state.entries = [];
      state.loaded = false;
    },
    refresh: (state) => {
      state.loaded = false;
    },
    switch: (state, action: PayloadAction<SwitchInventoryParams>) => {
      state.warehouseId = action.payload.warehouseId;
      state.loaded = false;
    }
  },
  extraReducers: (builder) => {
    builder.addCase(getInventory.fulfilled, (state, action) => {
      state.entries = action.payload.result.data;
      state.loaded = true;
    }).addCase(stockInventory.fulfilled, (state) => {
      state.loaded = false;
    }).addCase(transferInventory.fulfilled, (state) => {
      state.loaded = false;
    }).addCase(deleteInventory.fulfilled, (state) => {
      state.loaded = false;
    }).addMatcher(isRejected, (state, action) => {
      console.error(action.error);
    });
  }
});

export default inventoryManagementSlice.reducer;
export type { TransferInventoryEntry };
export const inventoryManagementActions = { ...inventoryManagementSlice.actions, getInventory, stockInventory, transferInventory, deleteInventory, updateInventory };
export const selectInventoryEntries = (root: RootState) => root.inventoryManagementReducer.entries;
export const selectInventoryEntriesLoaded = (root: RootState) => root.inventoryManagementReducer.loaded;
export const selectInventoryWarehouseId = (root: RootState) => root.inventoryManagementReducer.warehouseId;